Last update: Monday, October 10, 20:55.
This is a Stan implementation of Drew Linzer’s dynamic Bayesian election forecasting model, with some tweaks to incorporate national poll data, pollster house effects, correlated priors on state-by-state election results and comovement of public opinion across states.
For more details on the original model:
Linzer, D. 2013. “Dynamic Bayesian Forecasting of Presidential Elections in the States.” Journal of the American Statistical Association. 108(501): 124-134. (link)
The Stan and R files are available here.
10 most recent polls:
| Date (Midpoint) | Source | State | % Clinton | % Trump | N |
|---|---|---|---|---|---|
| 2016-10-08 | NBC | – | 56.8 | 43.2 | 362 |
| 2016-10-08 | Politico | – | 52.5 | 47.5 | 1239 |
| 2016-10-07 | Rasmussen | – | 54.2 | 45.8 | 1245 |
| 2016-10-07 | YouGov | – | 53.7 | 46.3 | 931 |
| 2016-10-06 | UPI | – | 53.2 | 46.8 | 1269 |
| 2016-10-06 | CBS | OH | 52.3 | 47.7 | 877 |
| 2016-10-06 | CBS | PA | 54.5 | 45.5 | 877 |
| 2016-10-06 | CBS | WI | 52.4 | 47.6 | 814 |
| 2016-10-05 | Quinnipiac | – | 52.9 | 47.1 | 904 |
| 2016-10-05 | UPI | AK | 43.6 | 56.4 | 287 |
829 polls available since April 01, 2016 (including 586 state polls and 243 national polls).
Note: the model is not accounting for the specific electoral vote allocation rules in place in Maine and Nebraska.
This graph shows the posterior median (blue line) and 90% credible interval (light blue area) of Hillary Clinton’s share of the national vote, derived from the weighted average of latent state-by-state vote intentions (using the same state weights as in the 2012 presidential election, adjusted for state adult population growth between 2011 and 2015). \[\pi^{clinton}[t, US] = \sum_{s \in S} \omega_s \cdot \textrm{logit}^{-1} (\mu_a[t] + \mu_b[t, s])\]
The thin blue lines represent 100 draws from the posterior distribution.
From today to November 8, Hillary Clinton’s share of the national vote is predicted to shrink partially towards the Time for Change prior (shown with the dotted black line).
Each national poll is represented as a dot (darker dots have narrower margins of error). Hillary Clinton’s national poll numbers seem to be running about 0.5 points below the level that would be consistent with the latent state-by-state vote intentions.
The following graphs show vote intention by state (with 100 draws from the posterior distribution represented as thin blue lines).
\[\pi^{clinton}[t,s] = \textrm{logit}^{-1} (\mu_a[t] + \mu_b[t, s])\]
As expected, 90% credible intervals (light blue areas) are wider for states and periods in which few polls are available and when state polls disagree with each other.
Most pro-Clinton polls:
| Poll Origin | Median | P95 | P05 |
|---|---|---|---|
| Raba Research | 1.9 | 0.4 | 3.6 |
| Saint Leo University | 1.6 | 0.1 | 3.2 |
| Siena | 1.5 | -0.1 | 3.1 |
| McClatchy | 1.4 | 0.0 | 2.9 |
| Public Religion Research Institute | 1.4 | 0.2 | 2.6 |
| ICITIZEN | 1.3 | 0.0 | 2.7 |
| WNEU | 1.3 | -0.5 | 3.3 |
| University of Delaware | 1.2 | -0.5 | 2.9 |
| GQR | 1.1 | -0.1 | 2.2 |
| Loras College | 1.1 | -0.5 | 2.8 |
Most pro-Trump polls:
| Poll Origin | Median | P95 | P05 |
|---|---|---|---|
| Rasmussen | -2.3 | -2.9 | -1.6 |
| UPI | -2.1 | -2.8 | -1.4 |
| Clout Research | -1.6 | -3.5 | 0.2 |
| PPIC | -1.6 | -3.2 | 0.0 |
| Emerson College Polling Society | -1.4 | -3.0 | 0.1 |
| InsideSources | -1.4 | -3.4 | 0.4 |
| FOX | -1.3 | -2.2 | -0.5 |
| GWU | -1.3 | -2.9 | 0.2 |
| Quinnipiac | -1.3 | -2.0 | -0.6 |
| IBD | -1.2 | -2.5 | 0.1 |
The runmodel.R script downloads state polls from the Princeton Election Consortium website and national polls from the HuffPost Pollster wesbite before processing the data.
The model ignores third-party candidates and undecided voters. I restrict each poll’s sample to respondents declaring vote intentions for Clinton or Trump, so that \(N = N^{clinton} + N^{trump}\).
When multiple polls are available by the same pollster, at the same date, and for the same state, I pick polls of likely voters rather than registered voters, and polls for which \(N^{clinton} + N^{trump}\) is the smallest (assuming that these are poll questions in which respondents are given the option to choose a third-party candidate, rather than “pushy” questions in which respondents are only asked to choose between the two leading candidates – these polls tend to be less favorable to Hillary Clinton).
Polls by the same pollster and of the same state with partially overlapping dates are dropped so that only the most recent, non-overlapping polls are retained.
To account for the fact that polls can be conducted over several days, I set the poll date to the midpoint between the day the poll started and the day it ended.
The model is in the file state and national polls.stan. It has a backward component, which aggregates poll history to derive unobserved latent vote intentions; and a forward component, which predicts how these unobserved latent vote intentions will evolve until election day. The backward and forward components are linked through priors about vote intention evolution: in each state, latent vote intentions follow a reverse random walk in which latent vote intentions “start” on election day \(T\) and evolve in random steps (correlated across states) as we go back in time. The starting point of the reverse random walk is the final state of vote intentions, which is assigned a reasonable prior, based on the Time-for-change, fundamentals-based election prediction model. The model reconciles the history of state and national polls with prior beliefs about final election results and about how vote intention evolves.
For each poll \(i\), the number of respondents declaring they intended to vote for Hillary Clinton \(N^{clinton}_i\) is drawn from a binomial distribution:
\[ N^{clinton}_i \sim \textrm{Binomial}(N_i, \pi^{clinton}_i) \]
where \(N_i\) is poll sample size, and \(\pi^{clinton}_i\) is share of the Clinton vote for this poll.
The model treats national and state polls differently.
If poll \(i\) is a state poll, I use a day/state/pollster multilevel model:
\[\textrm{logit} (\pi^{clinton}_i) = \mu_a[t_i] + \mu_b[t_i, s_i] + \mu_c[p_i] + u_i\]
What this model does is simply to decompose the log-odds of reported vote intentions towards Hillary Clinton \(\pi^{clinton}_i\) into a national component, shared across all states (\(\mu_a\)), a state-specific component (\(\mu_b\)), a pollster house effect (\(\mu_c\)), and a measurement noise term (\(u\))
On the day of the last available poll \(t_{last}\), the national component \(\mu_a[t_{last}]\) is set to zero, so that the predicted share of the Clinton vote in state \(s\) (net of pollster house effects and measurement noise) after that date and until election day \(T\) is:
\[\pi^{clinton}_{ts} = \textrm{logit}^{-1} (\mu_b[t, s])\]
To reduce the number of parameters, the model only takes weekly values for \(\mu_b\), so that:
\[\mu_b[t, s] = \mu_b^{weekly}[w_t, s]\]
where \(w_t\) is the week of day \(t\).
If poll \(i\) is a national poll, I use the same multilevel approach (with random intercepts for pollster house effects \(\mu_c\)) but I add a little tweak: the share of the Clinton vote in a national poll should also reflect the weighted average of state-by-state scores at the time of the poll. I model the share of vote intentions in national polls in the following way:
\[\textrm{logit} (\pi^{clinton}_i) = \textrm{logit}\left( \sum_{s \in \{1 \dots S\}} \omega_s \cdot \textrm{logit}^{-1} (\mu_a[t_i] + \mu_b^{weekly}[w_{t_i}, s_i]) \right) + \alpha + \mu_c[p_i] + u_i\]
where \(\omega_s\) represents the share of state \(s\) in the total votes of the set of polled states \(1 \dots S\) (based on 2012 turnout numbers adjusted for adult population growth in each state between 2011 and 2015). The \(\alpha\) parameter corrects for possible discrepancies between the national vote and the weighted average of state polls. Possible sources of discrepancies may include:
The idea is that while national poll levels may be off and generally not very indicative of the state of the race, national poll changes may contain valuable information to update \(\mu_a\) and (to a lesser extent) \(\mu_b\) parameters.
In order to smooth out vote intentions by state and obtain latent vote intentions at dates in which no polls were conducted, I use 2 reverse random walk priors for \(\mu_a\) and \(\mu_b^{weekly}\) from \(t_{last}\) to April 1:
\[\mu_b^{weekly}[w_t-1, s] \sim \textrm{Normal}(\mu_b^{weekly}[w_t, s], \sigma_b \cdot \sqrt{7})\]
\[\mu_a[t-1] \sim \textrm{Normal}(\mu_a[t], \sigma_a)\]
Both \(\sigma_a\) and \(\sigma_b\) are given uniform priors between 0 and 0.05.
Their posterior marginal distributions are shown below. The median day-to-day total standard deviation of vote intentions is about 0.5%. The model seems to find that most of the changes in latent vote intentions are attributable to national swings rather than state-specific swings (national swings account on average for about 84% of the total day-to-day variance).
I use a multivariate normal distribution for the prior of the final outcome. Its mean is based on the Time-for-Change model – which predicts that Hillary Clinton should receive 48.6% of the national vote (based on Q2 GDP figures, the current President’s approval rating and number of terms). The prior expects state final scores to remain on average centered around \(48.6\% + \delta_s\), where \(\delta_s\) is the excess Obama performance relative to the national vote in 2012 in state \(s\).
\[\mu_b[T, 1 \dots S] \sim \textrm{Multivariate Normal}(\textrm{logit} (0.486 + \delta_{1 \dots S}), \mathbf{\Sigma})\]
For the covariance matrix \(\mathbf{\Sigma}\), I set the variance to 0.05 and the covariance to 0.025 for all states and pairs of states – which corresponds to a correlation coefficient of 0.5 across states.
This prior is relatively imprecise as to the expected final scores in any given state; for example, in a state like Virginia, which Obama won by 52% in 2012 (a score identical to his national score), Hillary Clinton is expected to get 48.6% of the vote, with a 95% certainty that her score will not fall below 38% or exceed 59%.
State scores are also expected to be correlated with each other. For example, according to the prior (before looking at polling data), there is only a 3.5% chance that Hillary Clinton will perform worse in Virginia than in Texas. If the priors were independent, this unlikely event could happen with a 10% probability.
The covariance matrix implies that the correlation between the 2012 state scores and 2016 state priors is expected to be about 0.94 (as opposed to 0.89 if covariances were set to zero). The simulated distribution of correlations between state priors and 2012 scores is in line with observed correlations of state scores with previous election results since 1988 [http://election.princeton.edu/2016/06/02/the-realignment-myth/].
To put it differently, the model does not have a very precise prior about final scores, but it does assume that most of this uncertainty is attributable to national-level swings in vote intentions.
From election day to the date of the latest available poll \(t_{last}\), vote intentions by state “start” at \(\mu_b[T,s]\) and follow a random walk with correlated steps across states:
\[\mu_b^{weekly}[w_t-1, 1 \dots S] \sim \textrm{Multivariate Normal}(\mu_b^{weekly}[w_t, 1 \dots S], \mathbf{\Sigma_b^{walk}})\]
I set \(\mathbf{\Sigma_b^{walk}}\) so that all variances equal \(0.015^2 \times 7\) and all covariances equal 0.00118 (\(\rho =\) 0.75). This implies a 0.4% standard deviation in daily vote intentions changes in a state where Hillary Clinton’s score is close to 50%. To put it differently, the prior is 95% confident that Hillary Clinton’s score in any given state where she is currently polling around 50% should not move up or down by more than 4% over the remaining 29 days until the election.
The graph below shows shows 3 random draws from the prior distribution of \(mu_b\), to help visualize the assumptions regarding the forward component of the model.
Each pollster \(p\) can be biased towards Clinton or Trump:
\[\mu_c[p] \sim \textrm{Normal}(0, \sigma_c)\]
\[\sigma_c \sim \textrm{Uniform}(0, 0.2)\]
I give the \(\alpha\) parameter a prior centered around the observed distance of polled state voters from the national vote in 2012 (this was useful until early September, when lots of solid red states had still not been polled and the average polled state voter was more pro-Clinton than the average US voter.):
\[\bar{\delta_S} = \sum_{s \in \{1 \dots S\}} \omega_s \cdot \pi^{obama'12}_s - \pi^{obama'12}\]
\[\alpha \sim \textrm{Normal}(\textrm{logit} (\bar{\delta_S}), 0.2)\]
The noise term \(u_i\) is normally distributed around zero, with standard error \(\sigma_u^{national}\) for national polls, and \(\sigma_u^{state}\) for state polls. I give both standard errors a uniform distribution between 0 and 0.1.
With 4 chains and 2000 iterations (the first 1000 iterations of each chain are discarded), the model runs in about 10 minutes on my 4-core Intel i7 MacBookPro.
## [1] "Inference for Stan model: state and national polls."
## [2] "4 chains, each with iter=2000; warmup=1000; thin=1; "
## [3] "post-warmup draws per chain=1000, total post-warmup draws=4000."
## [4] ""
## [5] " mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat"
## [6] "alpha -0.02 0 0.01 -0.03 -0.02 -0.02 -0.01 0.00 2175 1.00"
## [7] "sigma_c 0.05 0 0.01 0.04 0.05 0.05 0.06 0.07 789 1.01"
## [8] "sigma_u_state 0.05 0 0.01 0.04 0.05 0.05 0.05 0.06 744 1.01"
## [9] "sigma_u_national 0.02 0 0.01 0.00 0.01 0.02 0.02 0.03 551 1.01"
## [10] "sigma_walk_a_past 0.02 0 0.00 0.01 0.02 0.02 0.02 0.03 1197 1.00"
## [11] "sigma_walk_b_past 0.01 0 0.00 0.00 0.01 0.01 0.01 0.01 573 1.01"
## [12] "mu_b[31,2] -0.19 0 0.09 -0.36 -0.25 -0.19 -0.13 -0.01 3028 1.00"
## [13] "mu_b[31,3] -0.38 0 0.09 -0.55 -0.44 -0.38 -0.33 -0.21 3533 1.00"
## [14] "mu_b[31,4] -0.28 0 0.09 -0.45 -0.34 -0.28 -0.22 -0.11 3069 1.00"
## [15] "mu_b[31,5] -0.03 0 0.08 -0.19 -0.08 -0.03 0.02 0.11 2956 1.00"
## [16] "mu_b[31,6] 0.63 0 0.08 0.47 0.57 0.63 0.68 0.78 3033 1.00"
## [17] "mu_b[31,7] 0.15 0 0.07 0.00 0.10 0.14 0.20 0.29 3029 1.00"
## [18] "mu_b[31,8] 0.37 0 0.08 0.20 0.31 0.37 0.42 0.53 3011 1.00"
## [19] "mu_b[31,9] 0.42 0 0.09 0.25 0.36 0.42 0.47 0.58 3129 1.00"
## [20] "mu_b[31,10] 0.09 0 0.07 -0.05 0.05 0.10 0.14 0.24 3085 1.00"
## [21] "mu_b[31,11] -0.05 0 0.08 -0.21 -0.10 -0.05 0.01 0.11 3128 1.00"
## [22] "mu_b[31,12] 0.81 0 0.09 0.64 0.75 0.81 0.88 1.00 3737 1.00"
## [23] "mu_b[31,13] 0.03 0 0.08 -0.13 -0.02 0.03 0.08 0.19 2903 1.00"
## [24] "mu_b[31,14] -0.56 0 0.09 -0.73 -0.62 -0.56 -0.50 -0.38 3250 1.00"
## [25] "mu_b[31,15] 0.45 0 0.08 0.29 0.40 0.45 0.50 0.61 2930 1.00"
## [26] "mu_b[31,16] -0.23 0 0.08 -0.40 -0.29 -0.23 -0.18 -0.07 2980 1.00"
## [27] "mu_b[31,17] -0.28 0 0.08 -0.45 -0.34 -0.28 -0.23 -0.12 3151 1.00"
## [28] "mu_b[31,18] -0.38 0 0.09 -0.55 -0.44 -0.38 -0.32 -0.21 3392 1.00"
## [29] "mu_b[31,19] -0.24 0 0.08 -0.40 -0.30 -0.24 -0.18 -0.08 2900 1.00"
## [30] "mu_b[31,20] 0.56 0 0.08 0.41 0.51 0.57 0.62 0.73 2827 1.00"
## [31] "mu_b[31,21] 0.69 0 0.08 0.54 0.63 0.69 0.74 0.85 3042 1.00"
## [32] "mu_b[31,22] 0.26 0 0.08 0.10 0.20 0.26 0.31 0.42 3017 1.00"
## [33] "mu_b[31,23] 0.20 0 0.08 0.04 0.14 0.20 0.25 0.36 2886 1.00"
## [34] "mu_b[31,24] 0.22 0 0.08 0.06 0.17 0.22 0.28 0.39 2738 1.00"
## [35] "mu_b[31,25] -0.11 0 0.08 -0.27 -0.16 -0.11 -0.06 0.05 2831 1.00"
## [36] "mu_b[31,26] -0.15 0 0.09 -0.32 -0.21 -0.15 -0.09 0.02 3451 1.00"
## [37] "mu_b[31,27] -0.24 0 0.09 -0.41 -0.30 -0.24 -0.19 -0.07 3127 1.00"
## [38] "mu_b[31,28] 0.08 0 0.08 -0.07 0.03 0.08 0.13 0.22 2660 1.00"
## [39] "mu_b[31,29] -0.37 0 0.10 -0.57 -0.44 -0.37 -0.31 -0.18 3150 1.00"
## [40] "mu_b[31,30] -0.31 0 0.09 -0.49 -0.37 -0.31 -0.25 -0.13 3325 1.00"
## [41] "mu_b[31,31] 0.16 0 0.08 0.00 0.11 0.16 0.21 0.31 2591 1.00"
## [42] "mu_b[31,32] 0.36 0 0.09 0.20 0.30 0.36 0.42 0.53 2986 1.00"
## [43] "mu_b[31,33] 0.28 0 0.08 0.11 0.22 0.28 0.34 0.44 2929 1.00"
## [44] "mu_b[31,34] 0.09 0 0.08 -0.06 0.04 0.09 0.15 0.25 2804 1.00"
## [45] "mu_b[31,35] 0.54 0 0.08 0.39 0.49 0.54 0.60 0.71 2714 1.00"
## [46] "mu_b[31,36] 0.07 0 0.07 -0.08 0.02 0.07 0.11 0.21 3005 1.00"
## [47] "mu_b[31,37] -0.52 0 0.09 -0.69 -0.58 -0.52 -0.46 -0.35 3093 1.00"
## [48] "mu_b[31,38] 0.30 0 0.08 0.14 0.24 0.30 0.35 0.46 2743 1.00"
## [49] "mu_b[31,39] 0.17 0 0.07 0.03 0.12 0.17 0.22 0.32 3176 1.00"
## [50] "mu_b[31,40] 0.46 0 0.10 0.27 0.39 0.46 0.52 0.65 3398 1.00"
## [51] "mu_b[31,41] -0.10 0 0.09 -0.27 -0.16 -0.10 -0.04 0.07 3080 1.00"
## [52] "mu_b[31,42] -0.27 0 0.10 -0.47 -0.33 -0.27 -0.20 -0.07 3546 1.00"
## [53] "mu_b[31,43] -0.30 0 0.08 -0.47 -0.36 -0.30 -0.25 -0.14 2402 1.00"
## [54] "mu_b[31,44] -0.18 0 0.08 -0.34 -0.23 -0.18 -0.13 -0.02 2895 1.00"
## [55] "mu_b[31,45] -0.49 0 0.09 -0.68 -0.55 -0.49 -0.42 -0.31 1884 1.00"
## [56] "mu_b[31,46] 0.22 0 0.08 0.07 0.17 0.22 0.27 0.37 3301 1.00"
## [57] "mu_b[31,47] 0.76 0 0.10 0.58 0.70 0.76 0.83 0.96 2754 1.00"
## [58] "mu_b[31,48] 0.37 0 0.08 0.21 0.32 0.37 0.43 0.54 3106 1.00"
## [59] "mu_b[31,49] 0.15 0 0.08 -0.01 0.09 0.15 0.20 0.29 3257 1.00"
## [60] "mu_b[31,50] -0.50 0 0.09 -0.67 -0.56 -0.50 -0.45 -0.34 3205 1.00"
## [61] "mu_b[31,51] -0.80 0 0.09 -0.99 -0.87 -0.80 -0.74 -0.62 3606 1.00"
## [62] ""
## [63] "Samples were drawn using NUTS(diag_e) at Mon Oct 10 20:55:26 2016."
## [64] "For each parameter, n_eff is a crude measure of effective sample size,"
## [65] "and Rhat is the potential scale reduction factor on split chains (at "
## [66] "convergence, Rhat=1)."